#include "stdafx.h"
#include "headers.h"

// TODO:
// If we have more than 1 scene acting simultaneously 
// make _camX _camY a member of CScene
INT16 _camX = 0, _camY = 0;

////////////////////////////////////////////////////////////////////////////////
// CTOR & DTOR /////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

CActor::CActor(CScene* scene, UINT8 type, UINT8 numParams)
{
	m_actType = type;
	m_actState = ACTSTATE_INACTIVE;
	m_params = new t_param[numParams];
	memset(m_params, 0, numParams * sizeof(t_param));
	m_scene = scene;

	m_anim = NULL;
	m_menu = NULL;
	//m_tileManager = NULL;
	m_fadeParams = NULL;
	m_moveX = NULL;
	m_moveY = NULL;
	m_blinkParams = NULL;
	m_shakeParams = NULL;

	SetPos(0, 0);
}

CActor::~CActor()
{
	SAFE_DEL_ARRAY(m_params);
	SAFE_DEL(m_anim);
	SAFE_DEL(m_menu);
	//if(m_actType == cConstants::ACTTYPE_TILESET)
	//{
	//	SAFE_DEL(m_tileManager);
	//}
	SAFE_DEL(m_fadeParams);
	SAFE_DEL(m_moveX);
	SAFE_DEL(m_moveY);
	SAFE_DEL(m_blinkParams);
	SAFE_DEL(m_shakeParams);
}

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

void CActor::Activate()
{
	// NOTE:
	// Activate the actor
	// If actor is already active, reset the action

	m_actState = ACTSTATE_ACTIVE;

	if(m_actType == cConstants::ACTTYPE_ANIM)
	{
		CSprite* sprite = GAME_INSTANCE->GetSprite((UINT8)m_params[cConstants::ACTPARAM_ANIM_SPRITEID]);
		if(m_anim == NULL)
		{
			m_anim = new CAnimObject(sprite);
		}
		else
		{
			m_anim->_anim_sprite = sprite;
		}
		m_anim->SetAnim((UINT8)m_params[cConstants::ACTPARAM_ANIM_ANIMID], m_params[cConstants::ACTPARAM_ANIM_LOOP] != 0);
		//m_anim->m_iTransform = ((UINT8)m_params[cConstants::ACTPARAM_ANIM_TRANS]);
	}

	if(m_actType == cConstants::ACTTYPE_FADE)
	{
		if(m_fadeParams == NULL)
		{
			m_fadeParams = new FadeParams();
		}
		m_fadeParams->elapsed = 0;
		m_fadeParams->alpha = 0;
	}

	if(m_actType == cConstants::ACTTYPE_CAMERA)
	{
		// To make sure that m_moveX and m_moveY are not NULL
		if(m_moveX == NULL)
		{
			m_moveX = new MoveParams();
			memset(m_moveX, 0, sizeof(MoveParams));
			m_moveX->pos = m_posX;
			m_moveX->done = true;
		}
		if(m_moveY == NULL)
		{
			m_moveY = new MoveParams();
			memset(m_moveY, 0, sizeof(MoveParams));
			m_moveY->pos = m_posY;
			m_moveY->done = true;
		}
	}
}

void CActor::Deactivate()
{
	m_actState = ACTSTATE_INACTIVE;

	// TODO: free action params
}

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

void CActor::Update()
{
	if(m_actState == ACTSTATE_INACTIVE) return;

	if(m_moveX != NULL && !m_moveX->done)
	{
		m_posX = UpdateMove(m_moveX);
	}
	if(m_moveY != NULL && !m_moveY->done)
	{
		m_posY = UpdateMove(m_moveY);
	}

	if(IsBlinking())
	{
		UpdateBlink();
	}
	if(IsShaking())
	{
		UpdateShake();
	}

	switch(m_actType)
	{
	case cConstants::ACTTYPE_ANIM:
		m_anim->UpdateAnimObject();
		break;

	case cConstants::ACTTYPE_TEXT:
		break;

	case cConstants::ACTTYPE_FADE:
		{
			m_fadeParams->elapsed += GAME_INSTANCE->m_frameDT * 1000;
			if(m_fadeParams->elapsed > m_params[cConstants::ACTPARAM_FADE_DURATION])
			{
				m_fadeParams->elapsed = m_params[cConstants::ACTPARAM_FADE_DURATION];
			}
			if(m_params[cConstants::ACTPARAM_FADE_TYPE] == cConstants::ACTFADE_TYPE_FADEIN)
			{
				m_fadeParams->alpha = CMath::LERP(m_params[cConstants::ACTPARAM_FADE_END], 0, (float)m_fadeParams->elapsed, 0, m_params[cConstants::ACTPARAM_FADE_DURATION]);
			}
			else
			{
				m_fadeParams->alpha = CMath::LERP(0, m_params[cConstants::ACTPARAM_FADE_END], (float)m_fadeParams->elapsed, 0, m_params[cConstants::ACTPARAM_FADE_DURATION]);
			}
			break;
		}

	case cConstants::ACTTYPE_RECT:
	case cConstants::ACTTYPE_TILESET:
		break;

	case cConstants::ACTTYPE_CAMERA:
		{
			if(!IsMoving())
			{
				// Focus
				CActor* focusedActor = (m_params[cConstants::ACTPARAM_CAMERA_FOCUSED_ACTOR] == cConstants::ACTSLOT_INVALID ? NULL : m_scene->GetActor(m_params[cConstants::ACTPARAM_CAMERA_FOCUSED_ACTOR]));

				if(focusedActor != NULL)
				{
					// Offset from focused actor to screen's LEFT - TOP
					INT16 offX = cConstants::SCR_HW;
					INT16 offY = cConstants::SCR_HH;

					// Destination of the camera
					INT16 destX = focusedActor->m_posX - offX;
					INT16 destY = focusedActor->m_posY - offY;

					// Limit scrolling
					if(destX < m_params[cConstants::ACTPARAM_CAMERA_MINX]) destX = m_params[cConstants::ACTPARAM_CAMERA_MINX];
					if(destX > m_params[cConstants::ACTPARAM_CAMERA_MAXX]) destX = m_params[cConstants::ACTPARAM_CAMERA_MAXX];
					if(destY < m_params[cConstants::ACTPARAM_CAMERA_MINY]) destY = m_params[cConstants::ACTPARAM_CAMERA_MINY];
					if(destY > m_params[cConstants::ACTPARAM_CAMERA_MAXY]) destY = m_params[cConstants::ACTPARAM_CAMERA_MAXY];

					// Movement of the camera
					float v_tmp = (float)(GAME_INSTANCE->m_frameDT * CAMERA_DEFAULT_SPEED);

					INT16 distX = abs(destX - m_posX);
					INT16 distY = abs(destY - m_posY);
					float vx = (distX == 0 ? 0 : v_tmp);
					float vy = (distY == 0 ? 0 : v_tmp);
					if(distX < CAMERA_SLOW_SPEED_RANGE)
					{
						vx = CMath::LERP(0, v_tmp, distX, 0, CAMERA_SLOW_SPEED_RANGE);
					}
					if(distY < CAMERA_SLOW_SPEED_RANGE)
					{
						vy = CMath::LERP(0, v_tmp, distY, 0, CAMERA_SLOW_SPEED_RANGE);
					}
					if(distX > 0 && distY > 0)
					{
						if(distX > distY)
						{
							vy = vy * distY / distX;
						}
						else if(distX < distY)
						{
							vx = vx * distX / distY;
						}
					}
					if(m_moveX->pos < destX)
					{
						m_moveX->pos += vx;
						if(m_moveX->pos >= destX)
						{
							m_moveX->pos = destX;
						}
					}
					else // if(m_moveX->pos > destX)
					{
						m_moveX->pos -= vx;
						if(m_moveX->pos <= destX)
						{
							m_moveX->pos = destX;
						}
					}
					if(m_moveY->pos < destY)
					{
						m_moveY->pos += vy;
						if(m_moveY->pos >= destY)
						{
							m_moveY->pos = destY;
						}
					}
					else // if(m_moveY->pos > destY)
					{
						m_moveY->pos -= vy;
						if(m_moveY->pos <= destY)
						{
							m_moveY->pos = destY;
						}
					}
					m_posX = (INT16)m_moveX->pos;
					m_posY = (INT16)m_moveY->pos;
				}
			}
			else
			{
				// Limit scrolling
				if(m_posX < m_params[cConstants::ACTPARAM_CAMERA_MINX])
				{
					m_posX = m_params[cConstants::ACTPARAM_CAMERA_MINX];
					m_moveX->pos = m_posX;
					m_moveX->done = true;
				}
				if(m_posX > m_params[cConstants::ACTPARAM_CAMERA_MAXX])
				{
					m_posX = m_params[cConstants::ACTPARAM_CAMERA_MAXX];
					m_moveX->pos = m_posX;
					m_moveX->done = true;
				}
				if(m_posY < m_params[cConstants::ACTPARAM_CAMERA_MINY])
				{
					m_posY = m_params[cConstants::ACTPARAM_CAMERA_MINY];
					m_moveY->pos = m_posY;
					m_moveY->done = true;
				}
				if(m_posY > m_params[cConstants::ACTPARAM_CAMERA_MAXY])
				{
					m_posY = m_params[cConstants::ACTPARAM_CAMERA_MAXY];
					m_moveY->pos = m_posY;
					m_moveY->done = true;
				}
			}

			// TODO:
			// Uncomment if we have more than 1 scene acting simultaneously
			// or if we have more than 1 camera in a scene
			//if(m_scene->GetCamera() == this)
			{
				_camX = m_posX;
				_camY = m_posY;
			}

			if(IsShaking())
			{
				_camX += m_shakeParams->x;
				_camY += m_shakeParams->y;
			}

			//if(m_tileManager != NULL)
			//{
			//	m_tileManager->SetPos(-m_posX, -m_posY);
			//}

			break;
		}

	case cConstants::ACTTYPE_MENU:
		m_menu->SetPos(m_posX, m_posY);
		if(!IsMoving())
		{
			m_menu->Update();
		}
		break;
	}
}

void CActor::Paint(bool inCam)
{
	if(m_actState == ACTSTATE_INACTIVE || IsBlinkHidden()) return;

	INT16 x = m_posX;
	INT16 y = m_posY;
	if(inCam)
	{
		x -= _camX;
		y -= _camY;
	}
	if(IsShaking())
	{
		x += m_shakeParams->x;
		y += m_shakeParams->y;
	}

	switch(m_actType)
	{
	case cConstants::ACTTYPE_ANIM:
		//m_anim->_anim_sprite->SetCurrentPalette((UINT8)m_params[cConstants::ACTPARAM_ANIM_PAL]);
		m_anim->SetPos(x, y);
		m_anim->DrawAnimObject(GAME_GRAPHICS);
		break;

	case cConstants::ACTTYPE_TEXT:
		{
			//GAME_INSTANCE->GetSprite((UINT8)m_params[cConstants::ACTPARAM_TEXT_FONT])->DrawPage(
			//	GAME_GRAPHICS,
			//	GAME_INSTANCE->GetText(m_params[cConstants::ACTPARAM_TEXT_TEXTID], m_params[cConstants::ACTPARAM_TEXT_SLOT]),
			//	GAME_INSTANCE->GetTextLength(m_params[cConstants::ACTPARAM_TEXT_TEXTID], m_params[cConstants::ACTPARAM_TEXT_SLOT]),
			//	x, y,
			//	m_params[cConstants::ACTPARAM_TEXT_W],
			//	m_params[cConstants::ACTPARAM_TEXT_ALIGN]);

			GAME_INSTANCE->DrawText(
				GAME_INSTANCE->GetSprite((UINT8)m_params[cConstants::ACTPARAM_TEXT_FONT]),
				m_params[cConstants::ACTPARAM_TEXT_TEXTID],
				m_params[cConstants::ACTPARAM_TEXT_SLOT],
				x, y,
				m_params[cConstants::ACTPARAM_TEXT_ALIGN]);
			break;
		}

	case cConstants::ACTTYPE_FADE:
		GAME_GRAPHICS->SetColorRGBA(
			m_params[cConstants::ACTPARAM_FADE_R],
			m_params[cConstants::ACTPARAM_FADE_G],
			m_params[cConstants::ACTPARAM_FADE_B],
			m_fadeParams->alpha);
		GAME_GRAPHICS->FillRect(x, y,
			m_params[cConstants::ACTPARAM_FADE_W],
			m_params[cConstants::ACTPARAM_FADE_H]);
		break;

	case cConstants::ACTTYPE_RECT:
		GAME_GRAPHICS->SetColorRGBA(
			m_params[cConstants::ACTPARAM_RECT_R],
			m_params[cConstants::ACTPARAM_RECT_G],
			m_params[cConstants::ACTPARAM_RECT_B],
			m_params[cConstants::ACTPARAM_RECT_A]);
		GAME_GRAPHICS->FillRect(x, y,
			m_params[cConstants::ACTPARAM_RECT_W],
			m_params[cConstants::ACTPARAM_RECT_H]);
		break;

	//case cConstants::ACTTYPE_TILESET:
	//	if(m_tileManager != m_scene->GetTileManager())
	//	{
	//		m_tileManager->SetPos(x, y);
	//		m_tileManager->DrawBackgroundLayers();
	//		m_tileManager->DrawOverlayLayers();
	//	}
	//	break;

	case cConstants::ACTTYPE_CAMERA:
		break;

	case cConstants::ACTTYPE_MENU:
		m_menu->Paint();
		break;
	}
}

////////////////////////////////////////////////////////////////////////////////
// Params //////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

void CActor::SetParam(UINT8 param, t_param value)
{
	// NOTE:
	// If actor is not activated => just set parameters
	// If actor is activating => update current action if possible

	//if(m_actType == cConstants::ACTTYPE_TILESET
	//	&& (param == cConstants::ACTPARAM_TILESET_SPRITEID
	//		|| param == cConstants::ACTPARAM_TILESET_PAL))
	//{
	//	CSprite* sprite = GAME_INSTANCE->GetSprite((UINT8)m_params[cConstants::ACTPARAM_TILESET_SPRITEID]);
	//	sprite->SetCurrentPalette((UINT8)m_params[cConstants::ACTPARAM_TILESET_PAL]);
	//	for(INT8 i=0; i<m_tileManager->GetNumLayers(); i++)
	//	{
	//		m_tileManager->SetTileset(i, sprite);
	//	}
	//}

	m_params[param] = value;

	if(m_actState == ACTSTATE_INACTIVE) return;

	if(m_actType == cConstants::ACTTYPE_ANIM)
	{
		if(param == cConstants::ACTPARAM_ANIM_SPRITEID)
		{
			m_anim->_anim_sprite = GAME_INSTANCE->GetSprite((UINT8)m_params[cConstants::ACTPARAM_ANIM_SPRITEID]);
		}
		else if(param == cConstants::ACTPARAM_ANIM_ANIMID || param == cConstants::ACTPARAM_ANIM_LOOP)
		{
			m_anim->SetAnim((UINT8)m_params[cConstants::ACTPARAM_ANIM_ANIMID], (UINT8)m_params[cConstants::ACTPARAM_ANIM_LOOP] != 0);
		}
		else if(param == cConstants::ACTPARAM_ANIM_TRANS)
		{
			//m_anim->m_iTransform = (UINT8)m_params[cConstants::ACTPARAM_ANIM_TRANS];
		}
	}

	if(m_actType == cConstants::ACTTYPE_CAMERA && param == cConstants::ACTPARAM_CAMERA_FOCUSED_ACTOR)
	{
		if(m_moveX != NULL)
		{
			m_moveX->pos = m_posX;
		}
		if(m_moveY != NULL)
		{
			m_moveY->pos = m_posY;
		}
	}
}

////////////////////////////////////////////////////////////////////////////////
// Position ////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

void CActor::SetPos(INT16 x, INT16 y)
{
	m_posX = x;
	m_posY = y;

	// Stop any movement
	if(m_moveX != NULL) m_moveX->done = true;
	if(m_moveY != NULL) m_moveY->done = true;
}

////////////////////////////////////////////////////////////////////////////////
// Move ////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

void CActor::Move(UINT8 dir, UINT8 type, INT16 dest, INT16 p1, INT16 p2, INT16 p3, INT16 p4)
{
	// Stop moving
	if(type == cConstants::MOVTYPE_STOP)
	{
		if(dir == cConstants::MOVDIR_X && m_moveX != NULL)
		{
			m_moveX->done = true;
		}
		if(dir == cConstants::MOVDIR_Y && m_moveY != NULL)
		{
			m_moveY->done = true;
		}
		return;
	}

	// Offsets?
	bool off = false;
	if(dir == cConstants::MOVDIR_OFF_X)
	{
		dir = cConstants::MOVDIR_X;
		off = true;
	}
	if(dir == cConstants::MOVDIR_OFF_Y)
	{
		dir = cConstants::MOVDIR_Y;
		off = true;
	}

	MoveParams* mp = NULL;
	INT16 pos = 0;
	if(dir == cConstants::MOVDIR_X)
	{
		if(m_moveX == NULL)
		{
			m_moveX = new MoveParams();
		}
		mp = m_moveX;
		pos = m_posX;
	}
	if(dir == cConstants::MOVDIR_Y)
	{
		if(m_moveY == NULL)
		{
			m_moveY = new MoveParams();
		}
		mp = m_moveY;
		pos = m_posY;
	}
	memset(mp, 0, sizeof(MoveParams));
	mp->type = type;
	mp->dest = dest;
	mp->pos = pos;
	switch(type)
	{
	case cConstants::MOVTYPE_STRAIGHT_T:
		mp->p1 = p1 / 1000.0f;		// dur: millis => s
		break;

	case cConstants::MOVTYPE_STRAIGHT_V:
		mp->p1 = p1;				// v > 0
		break;

	case cConstants::MOVTYPE_STRAIGHT_VA:
		mp->p1 = p1;				// v
		mp->p2 = p2;				// a
		mp->p3 = p3 / 1000.0f;		// dur: millis => s
		mp->p4 = pos;				// x0
		break;

	case cConstants::MOVTYPE_SMOOTH_T:
		mp->p1 = p1 / 1000.0f;		// dur: millis => s
		break;

	case cConstants::MOVTYPE_DIV:
		mp->p1 = p1;				// v
		mp->p2 = p2;				// div
		break;

	case cConstants::MOVTYPE_BOUNCE:
		mp->p1 = p1;				// v
		mp->p2 = p2;				// a
		mp->p3 = p3;				// count
		mp->p4 = pos;				// x0
		break;

	case cConstants::MOVTYPE_SIN:
		mp->p1 = p1;				// amp
		mp->p2 = p2;				// v
		mp->p3 = p3;				// ang
		mp->p4 = p4 / 1000.0f;		// dur: millis => s
		break;
	}

	if(off)
	{
		mp->dest += pos;
	}
}

INT16 CActor::UpdateMove(MoveParams *mp)
{
	switch(mp->type)
	{
	case cConstants::MOVTYPE_STRAIGHT_T:
		{
			mp->t += GAME_INSTANCE->m_frameDT;
			if(mp->t >= mp->p1)
			{
				mp->done = true;
				return mp->dest;
			}
			return (INT16)CMath::LERP(mp->pos, mp->dest, (float)mp->t, 0, mp->p1);
		}

	case cConstants::MOVTYPE_STRAIGHT_V:
		{
			mp->t += GAME_INSTANCE->m_frameDT;
			float s = (float)(mp->p1 * mp->t);
			if(s >= abs(mp->dest - mp->pos))
			{
				mp->done = true;
				return mp->dest;			
			}
			else if(mp->pos > mp->dest)
			{
				return (INT16)(mp->pos - s);
			}
			else // if(mp->pos < mp->dest)
			{
				return (INT16)(mp->pos + s);
			}
		}

	case cConstants::MOVTYPE_STRAIGHT_VA:
		{
			mp->t += GAME_INSTANCE->m_frameDT;
			float s = (float)(mp->p4 + mp->p1 * mp->t + (mp->p2 * mp->t * mp->t) / 2);
			if(mp->p3 > 0 && mp->t >= mp->p3)
			{
				mp->dest = (INT16)s;
				mp->done = true;
				return mp->dest;
			}
			else
			{
				return (INT16)s;
			}
		}

	case cConstants::MOVTYPE_SMOOTH_T:
		{
			mp->t += GAME_INSTANCE->m_frameDT;
			if(mp->t >= mp->p1)
			{
				mp->done = true;
				return mp->dest;
			}
			float a = CMath::LERP(0, 2, (float)mp->t, 0, mp->p1);
			return (INT16)CMath::LERP(mp->pos, mp->dest, -0.25f * a * a + a);
		}

	case cConstants::MOVTYPE_DIV:
		{
			if(abs(mp->dest - mp->pos) <= 1)
			{
				mp->done = true;
				return mp->dest;
			}
			else
			{
				float s = (mp->dest - mp->pos) / mp->p2;
				float v = (float)GAME_INSTANCE->m_frameDT * mp->p1;
				if(s < -v) s = -v;
				if(s > v) s = v;
				mp->pos += s;
				return (INT16)mp->pos;
			}
		}

	case cConstants::MOVTYPE_BOUNCE:
		{
			mp->t += GAME_INSTANCE->m_frameDT;
			float pos = (float)(mp->p4 + mp->p1 * mp->t + (mp->p2 * mp->t * mp->t) / 2);
			if((mp->p2 > 0 && pos > mp->dest) || (mp->p2 < 0 && pos < mp->dest))
			{
				mp->p1 = -(float)((mp->p1 + mp->p2 * mp->t) * 3 / 4);
				mp->p3--;
				mp->p4 = mp->dest;
				mp->t = 0;
				if(mp->p3 <= 0 || abs(mp->p1) <= 1)
				{
					mp->done = true;
				}
				return mp->dest;
			}
			else
			{
				return (INT16)pos;
			}
		}

	case cConstants::MOVTYPE_SIN:
		{
			INT16 a = (INT16)mp->p1;
			mp->t += GAME_INSTANCE->m_frameDT;
			if(mp->p4 > 0)
			{
				if(mp->t >= mp->p4)
				{
					mp->done = true;
					return mp->dest;
				}
				else
				{
					a = (INT16)CMath::LERP(mp->p1, 0, (float)mp->t, 0, mp->p4);
				}
			}
			return (mp->dest + (INT16)(a * sin((mp->p2 * mp->t + mp->p3) * PI / 180)));
		}
	}

	// Error
	return 0;
}

////////////////////////////////////////////////////////////////////////////////
// Blink ///////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

void CActor::Blink(UINT16 millis, UINT16 duration)
{
	if(m_blinkParams == NULL)
	{
		m_blinkParams = new BlinkParams();
	}
	m_blinkParams->t = 0;
	m_blinkParams->millis = millis;
	m_blinkParams->dur = duration;
	m_blinkParams->done = false;
}

void CActor::UpdateBlink()
{
	m_blinkParams->t += GAME_INSTANCE->m_frameDT * 1000;
	if(m_blinkParams->dur > 0 && m_blinkParams->t > m_blinkParams->dur)
	{
		m_blinkParams->t = 0;
		m_blinkParams->done = true;
	}
}

////////////////////////////////////////////////////////////////////////////////
// Shake ///////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

void CActor::Shake(UINT8 type, INT8 rx, INT8 ry, UINT16 dur)
{
	if(m_shakeParams == NULL)
	{
		m_shakeParams = new ShakeParams();
	}

	if(type != cConstants::SHAKETYPE_RANDOM
		&& type != cConstants::SHAKETYPE_EVEN
		&& dur == 0)
	{
		// Duration required but no duration passed
		m_shakeParams->done = true;
		return;
	}

	memset(m_shakeParams, 0, sizeof(ShakeParams));
	m_shakeParams->type = type;
	m_shakeParams->rx = rx;
	m_shakeParams->ry = ry;
	m_shakeParams->dur = dur;
}

void CActor::UpdateShake()
{
	if(m_shakeParams->dur > 0)
	{
		m_shakeParams->t += (GAME_INSTANCE->m_frameDT * 1000);
		if(m_shakeParams->t >= m_shakeParams->dur)
		{
			m_shakeParams->done = true;
			return;
		}
	}

	#define SHAKE_UPDATE_TIMER 0.025f

	switch(m_shakeParams->type)
	{
	case cConstants::SHAKETYPE_RANDOM:
	case cConstants::SHAKETYPE_RANDOM_DECREASE:
		{
			m_shakeParams->t_shake += GAME_INSTANCE->m_frameDT;
			if(m_shakeParams->t_shake >= SHAKE_UPDATE_TIMER)
			{
				m_shakeParams->t_shake = 0;
				if(m_shakeParams->type == cConstants::SHAKETYPE_RANDOM)
				{
					m_shakeParams->x = (INT8)CMath::RANDOM(-m_shakeParams->rx, m_shakeParams->rx);
					m_shakeParams->y = (INT8)CMath::RANDOM(-m_shakeParams->ry, m_shakeParams->ry);
				}
				else
				{
					INT8 rx = (INT8)CMath::LERP(m_shakeParams->rx, 0, (float)m_shakeParams->t, 0, m_shakeParams->dur);
					INT8 ry = (INT8)CMath::LERP(m_shakeParams->ry, 0, (float)m_shakeParams->t, 0, m_shakeParams->dur);
					m_shakeParams->x = (INT8)CMath::RANDOM(-rx, rx);
					m_shakeParams->y = (INT8)CMath::RANDOM(-ry, ry);
				}
			}
			break;
		}

	case cConstants::SHAKETYPE_HEAVY:
		{
			m_shakeParams->x = (INT8)CMath::LERP(m_shakeParams->rx, 0, (float)m_shakeParams->t, 0, m_shakeParams->dur);
			m_shakeParams->y = (INT8)CMath::LERP(m_shakeParams->ry, 0, (float)m_shakeParams->t, 0, m_shakeParams->dur);
			break;
		}

	case cConstants::SHAKETYPE_EVEN:
	case cConstants::SHAKETYPE_EVEN_DECREASE:
		{
			m_shakeParams->t_shake += GAME_INSTANCE->m_frameDT;
			if(m_shakeParams->t_shake >= SHAKE_UPDATE_TIMER)
			{
				m_shakeParams->t_shake = 0;
				INT8 rx, ry;
				if(m_shakeParams->type == cConstants::SHAKETYPE_EVEN)
				{
					rx = m_shakeParams->rx;
					ry = m_shakeParams->ry;
				}
				else
				{
					rx = (INT8)CMath::LERP(m_shakeParams->rx, 0, (float)m_shakeParams->t, 0, m_shakeParams->dur);
					ry = (INT8)CMath::LERP(m_shakeParams->ry, 0, (float)m_shakeParams->t, 0, m_shakeParams->dur);
				}
				if(m_shakeParams->x <= -rx || m_shakeParams->x == 0)
				{
					m_shakeParams->x = rx;
				}
				else if(m_shakeParams->x >= rx)
				{
					m_shakeParams->x = -rx;
				}
				if(m_shakeParams->y <= -ry || m_shakeParams->y == 0)
				{
					m_shakeParams->y = ry;
				}
				else if(m_shakeParams->y >= ry)
				{
					m_shakeParams->y = -ry;
				}
			}
			break;
		}

	}
}

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

void CActor::SetCameraScrollingLimit(INT16 minX, INT16 minY, INT16 maxX, INT16 maxY)
{
	m_params[cConstants::ACTPARAM_CAMERA_MINX] = minX;
	m_params[cConstants::ACTPARAM_CAMERA_MINY] = minY;
	m_params[cConstants::ACTPARAM_CAMERA_MAXX] = maxX;
	m_params[cConstants::ACTPARAM_CAMERA_MAXY] = maxY;
}

bool CActor::IsActionFinished()
{
	if(IsMoving() || IsBlinking() || IsShaking()) return false;

	switch(m_actType)
	{
	case cConstants::ACTTYPE_ANIM:
		if(m_anim != NULL && !m_anim->_is_loop && !m_anim->IsCurrentAnimStop())
			return false;
		return true;

	case cConstants::ACTTYPE_FADE:
		if(m_fadeParams != NULL
			&& m_fadeParams->elapsed < m_params[cConstants::ACTPARAM_FADE_DURATION])
			return false;
		return true;
	}

	return true;
}

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////